1   //  Copyright 2008, 2009, 2012 The Apache Software Foundation
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package org.apache.tapestry5.internal.services;
16  
17  import org.apache.tapestry5.ComponentEventCallback;
18  import org.apache.tapestry5.EventConstants;
19  import org.apache.tapestry5.internal.structure.ComponentPageElement;
20  import org.apache.tapestry5.internal.structure.Page;
21  import org.apache.tapestry5.internal.util.Holder;
22  import org.apache.tapestry5.ioc.annotations.PostInjection;
23  import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
24  import org.apache.tapestry5.ioc.services.TypeCoercer;
25  import org.apache.tapestry5.model.ComponentModel;
26  import org.apache.tapestry5.services.ComponentClasses;
27  import org.apache.tapestry5.services.InvalidationEventHub;
28  import org.apache.tapestry5.services.InvalidationListener;
29  
30  import java.util.Map;
31  
32  public class PageActivationContextCollectorImpl implements PageActivationContextCollector
33  {
34      private final Object[] EMPTY = new Object[0];
35  
36      private final TypeCoercer typeCoercer;
37  
38      private final ComponentModelSource modelSource;
39  
40      private final RequestPageCache requestPageCache;
41  
42      /**
43       * Keyed on *canonical* page name, value indicates whether the page has a passivate event handler.
44       */
45      private final Map<String, Boolean> cache = CollectionFactory.newConcurrentMap();
46  
47      public PageActivationContextCollectorImpl(TypeCoercer typeCoercer, RequestPageCache requestPageCache,
48                                                ComponentModelSource modelSource)
49      {
50          this.typeCoercer = typeCoercer;
51          this.requestPageCache = requestPageCache;
52          this.modelSource = modelSource;
53  
54      }
55  
56      @PostInjection
57      public void setupInvalidation(@ComponentClasses InvalidationEventHub invalidationEventHub)
58      {
59          invalidationEventHub.clearOnInvalidation(cache);
60      }
61  
62      public Object[] collectPageActivationContext(String pageName)
63      {
64          Boolean hasHandler = cache.get(pageName);
65  
66          if (hasHandler == null)
67          {
68              ComponentModel model = modelSource.getPageModel(pageName);
69  
70              hasHandler = model.handlesEvent(EventConstants.PASSIVATE);
71  
72              cache.put(pageName, hasHandler);
73          }
74  
75          // If no handler for the event, then no need to fire the event (and more importantly,
76          // no need to obtain a page instance!)
77  
78          if (!hasHandler)
79              return EMPTY;
80  
81          // Get or create a page instance and trigger the event.
82  
83          Page page = requestPageCache.get(pageName);
84  
85          ComponentPageElement element = page.getRootElement();
86  
87          final Holder<Object[]> holder = Holder.create();
88  
89          ComponentEventCallback callback = new ComponentEventCallback()
90          {
91              public boolean handleResult(Object result)
92              {
93                  holder.put(typeCoercer.coerce(result, Object[].class));
94  
95                  // We've got the value, stop the event.
96  
97                  return true;
98              }
99          };
100 
101         element.triggerEvent(EventConstants.PASSIVATE, null, callback);
102 
103         if (!holder.hasValue()) return EMPTY;
104 
105         return holder.get();
106     }
107 }